﻿// Learn more about F# at http://fsharp.net

namespace Lilium.Web.Mvc

open System.Runtime.CompilerServices
open System.Web.Mvc

type IControllerMethods =
    abstract member CreateView : string * string * obj -> ActionResult

[<Extension>]
module Workflow = 

    open System

    open Monad.Utils
    open Monad.Combinators

    type 'a WorkflowData = Model of 'a | Error | Nothing

    type 'a WorkflowState (methods, data) =
        member this.Data = data
        member this.SetData data = WorkflowState (methods, data)

    type WorkflowBuilder() = 
        // a -> m a
        member this.Return model = Model model
        // m a -> (a -> m b) -> m b
        member this.Bind (workflow, f) = 
            match workflow with
            | Model model -> f model

    let workflow = WorkflowBuilder()

    let inline execute controller (workflow : WorkflowState<obj> -> 'a WorkflowState) =

        let controllerMethods = { 
            new IControllerMethods with 
                member this.CreateView (viewName, masterName, model) = (^c: (member CreateView: string * string * obj -> ActionResult) controller, viewName, masterName, model) }
        
        let workflowState = WorkflowState(controllerMethods, Nothing)

        let result = workflow workflowState
        
        match result.Data with 
        | Nothing -> controllerMethods.CreateView(null, null, null)
        | Model model -> controllerMethods.CreateView(null, null, model)

    (*
    [<Extension>]
    let execute workflow : ActionResult =  -- конетоллер сюда как параметр
        match workflow with 
        | Model model -> failwith "test"

    let inline initWorkflow () : ('c -> Workflow<obj>)  = // delay?
        fun controller -> 
            let controllerMethods = { 
                new IControllerMethods with 
                    member this.CreateView viewName masterName model = (^c: (member CreateView: string * string * obj -> ActionResult) controller, viewName, masterName, model) }
        
            Workflow (controllerMethods, Nothing)
    *)
    // C# Support

    let EmptyWorkflow =
        new Func<WorkflowState<obj>, WorkflowState<obj>>(fun workflowState -> workflowState (* здесь вызов инициализации *) )

    [<Extension>]
    let inline ExecuteWorkflow (controller: IControllerMethods, workflow) = 
        execute controller (applyFunc workflow)

    [<Extension>]
    let inline Select (m, f) = 
        liftM workflow (applyFunc f) m

















(*
let inline liftM m f m_a =
    let unit x = (^m: (member Return: ^b -> ^m_b) m, x)
    let bind m_a f = (^m: (member Bind: ^m_a -> (^a -> ^m_b) -> ^m_b) m, m_a, f)
    bind m_a (fun a -> unit (f a))

let inline liftM2 m1 m2 f m_a1 m_a2 =
    let unit1 x = (^m1: (member Return: ^b -> ^m_b) m1, x)
    let bind1 m_a1 f = (^m1: (member Bind: ^m_a1 -> (^a1 -> ^m_b) -> ^m_b) m1, m_a1, f)
    let unit2 x = (^m2: (member Return: ^b -> ^m_b) m2, x)
    let bind2 m_a2 f = (^m2: (member Bind: ^m_a2 -> (^a2 -> ^m_b) -> ^m_b) m2, m_a2, f)
    bind1 m_a1 (fun a1 -> bind2 m_a2 (fun a2 -> unit2 (f a1 a2)))
*)
